/**
 * 文本对比工具 - 增强版
 */

// ========== FileHandler 类 ==========
class FileHandler {
    constructor(comparator) {
        this.comparator = comparator;
        this.maxFileSize = 10 * 1024 * 1024; // 10MB
    }

    /**
     * 导入文件
     * @param {string} target - 'original' 或 'modified'
     */
    async importFile(target) {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.txt,.js,.json,.html,.css,.md,.log,.xml,.yaml,.yml,.csv,.sql';

        input.onchange = async (e) => {
            const file = e.target.files[0];
            if (!file) return;

            // 验证文件大小
            if (file.size > this.maxFileSize) {
                UIUtils.showToast('文件大小超过10MB限制', 'error');
                return;
            }

            try {
                const text = await this.readFile(file);
                this.comparator.setText(target, text);
                UIUtils.showToast(`文件 "${file.name}" 导入成功`, 'success');
            } catch (error) {
                UIUtils.showToast('文件读取失败', 'error');
                console.error('File read error:', error);
            }
        };

        input.click();
    }

    /**
     * 读取文件内容
     * @param {File} file
     * @returns {Promise<string>}
     */
    readFile(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = (e) => resolve(e.target.result);
            reader.onerror = (e) => reject(e);
            reader.readAsText(file, 'UTF-8');
        });
    }

    /**
     * 导出文件
     * @param {string} target - 'original' 或 'modified'
     */
    exportFile(target) {
        const text = this.comparator.getText(target);
        if (!text) {
            UIUtils.showToast('没有内容可导出', 'warning');
            return;
        }

        const filename = `${target}-text-${Date.now()}.txt`;
        const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
        const url = URL.createObjectURL(blob);

        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        a.click();

        // 清理
        setTimeout(() => URL.revokeObjectURL(url), 100);
        UIUtils.showToast(`文件 "${filename}" 导出成功`, 'success');
    }
}

// ========== SortManager 类 ==========
class SortManager {
    constructor(comparator) {
        this.comparator = comparator;
        this.dropdowns = new Map();
    }

    /**
     * 初始化下拉菜单
     * @param {string} target - 'original' 或 'modified'
     * @param {HTMLElement} button - 排序按钮
     * @param {HTMLElement} menu - 下拉菜单
     */
    initDropdown(target, button, menu) {
        this.dropdowns.set(target, { button, menu, isOpen: false });

        // 按钮点击事件
        button.addEventListener('click', (e) => {
            e.stopPropagation();
            this.toggleDropdown(target);
        });

        // 点击外部关闭
        document.addEventListener('click', () => {
            this.closeAllDropdowns();
        });

        // 排序选项点击
        menu.querySelectorAll('.sort-option').forEach(option => {
            option.addEventListener('click', (e) => {
                e.stopPropagation();
                const order = option.dataset.type;
                this.sort(target, order);
                this.closeAllDropdowns();
            });
        });
    }

    /**
     * 排序文本
     * @param {string} target - 'original' 或 'modified'
     * @param {string} order - 'asc' 或 'desc'
     */
    sort(target, order) {
        const text = this.comparator.getText(target);
        if (!text) {
            UIUtils.showToast('没有内容可排序', 'warning');
            return;
        }

        const lines = text.split('\n');
        lines.sort((a, b) => {
            if (order === 'asc') {
                return a.localeCompare(b);
            } else {
                return b.localeCompare(a);
            }
        });

        const sortedText = lines.join('\n');
        this.comparator.setText(target, sortedText);

        const orderText = order === 'asc' ? '升序' : '降序';
        UIUtils.showToast(`文本已按${orderText}排序`, 'success');
    }

    /**
     * 切换下拉菜单
     * @param {string} target
     */
    toggleDropdown(target) {
        const dropdown = this.dropdowns.get(target);
        if (!dropdown) return;

        // 关闭其他下拉菜单
        this.dropdowns.forEach((d, t) => {
            if (t !== target && d.isOpen) {
                d.menu.classList.remove('show');
                d.isOpen = false;
            }
        });

        // 切换当前下拉菜单
        dropdown.isOpen = !dropdown.isOpen;
        if (dropdown.isOpen) {
            dropdown.menu.classList.add('show');
        } else {
            dropdown.menu.classList.remove('show');
        }
    }

    /**
     * 关闭所有下拉菜单
     */
    closeAllDropdowns() {
        this.dropdowns.forEach(dropdown => {
            dropdown.menu.classList.remove('show');
            dropdown.isOpen = false;
        });
    }
}

// ========== MergeManager 类 ==========
class MergeManager {
    constructor(comparator) {
        this.comparator = comparator;
    }

    /**
     * 合并单个差异块
     * @param {number} index - 差异索引
     * @param {string} direction - 'left' 或 'right'
     */
    mergeSingle(index, direction) {
        const diff = this.comparator.diffs[index];
        if (!diff) return;

        const originalLines = this.comparator.originalText.split('\n');
        const modifiedLines = this.comparator.modifiedText.split('\n');

        if (direction === 'left') {
            // 从原始到修改
            if (diff.type === 'removed') {
                modifiedLines.splice(diff.lineNum1 - 1, 0, diff.line1);
            } else if (diff.type === 'modified') {
                modifiedLines[diff.lineNum2 - 1] = diff.line1;
            } else if (diff.type === 'added') {
                modifiedLines.splice(diff.lineNum2 - 1, 1);
            }
            this.comparator.modifiedText = modifiedLines.join('\n');
            this.comparator.setText('modified', this.comparator.modifiedText);
        } else {
            // 从修改到原始
            if (diff.type === 'added') {
                originalLines.splice(diff.lineNum2 - 1, 0, diff.line2);
            } else if (diff.type === 'modified') {
                originalLines[diff.lineNum1 - 1] = diff.line2;
            } else if (diff.type === 'removed') {
                originalLines.splice(diff.lineNum1 - 1, 1);
            }
            this.comparator.originalText = originalLines.join('\n');
            this.comparator.setText('original', this.comparator.originalText);
        }

        // 重新对比
        this.comparator.compare();
    }

    /**
     * 合并所有差异
     * @param {string} direction - 'left' 或 'right'
     */
    mergeAll(direction) {
        if (direction === 'left') {
            // 复制原始到修改
            this.comparator.modifiedText = this.comparator.originalText;
            this.comparator.setText('modified', this.comparator.modifiedText);
        } else {
            // 复制修改到原始
            this.comparator.originalText = this.comparator.modifiedText;
            this.comparator.setText('original', this.comparator.originalText);
        }

        UIUtils.showToast('所有更改已合并', 'success');
        this.comparator.compare();
    }
}

// ========== StatisticsManager 类 ==========
class StatisticsManager {
    constructor(comparator) {
        this.comparator = comparator;
        this.originalStatsElement = null;
        this.modifiedStatsElement = null;
    }

    /**
     * 初始化统计元素
     * @param {HTMLElement} originalStats
     * @param {HTMLElement} modifiedStats
     */
    init(originalStats, modifiedStats) {
        this.originalStatsElement = originalStats;
        this.modifiedStatsElement = modifiedStats;
    }

    /**
     * 更新统计信息
     */
    update() {
        const diffs = this.comparator.diffs;

        // 统计各类型数量
        let added = 0;
        let removed = 0;
        let modified = 0;
        let unchanged = 0;

        diffs.forEach(diff => {
            switch (diff.type) {
                case 'added':
                    added++;
                    break;
                case 'removed':
                    removed++;
                    break;
                case 'modified':
                    modified++;
                    break;
                case 'equal':
                    unchanged++;
                    break;
            }
        });

        // 计算总行数
        const originalLines = this.comparator.originalText.split('\n').length;
        const modifiedLines = this.comparator.modifiedText.split('\n').length;

        // 更新显示
        if (this.originalStatsElement) {
            this.originalStatsElement.innerHTML = `
                <span class="stat-item">${originalLines} 行</span>
                ${removed > 0 ? `<span class="stat-removed">-${removed}</span>` : ''}
                ${modified > 0 ? `<span class="stat-modified">~${modified}</span>` : ''}
            `;
        }

        if (this.modifiedStatsElement) {
            this.modifiedStatsElement.innerHTML = `
                <span class="stat-item">${modifiedLines} 行</span>
                ${added > 0 ? `<span class="stat-added">+${added}</span>` : ''}
                ${modified > 0 ? `<span class="stat-modified">~${modified}</span>` : ''}
            `;
        }

        // 显示统计摘要
        this.showSummary(diffs, added, removed, modified);
    }

    /**
     * 显示统计摘要
     * @param {Array} diffs - 差异数组
     * @param {number} added - 新增行数
     * @param {number} removed - 删除行数
     * @param {number} modified - 修改行数
     */
    showSummary(diffs, added, removed, modified) {
        const summaries = [];

        // 收集各类型的行号
        const modifiedLines = [];
        const addedLines = [];
        const removedLines = [];

        let lineNum1 = 0;
        let lineNum2 = 0;

        diffs.forEach(diff => {
            if (diff.type === 'equal') {
                lineNum1++;
                lineNum2++;
            } else if (diff.type === 'modified') {
                lineNum1++;
                lineNum2++;
                modifiedLines.push(lineNum1);
            } else if (diff.type === 'added') {
                lineNum2++;
                addedLines.push(lineNum2);
            } else if (diff.type === 'removed') {
                lineNum1++;
                removedLines.push(lineNum1);
            }
        });

        // 构建摘要信息
        if (modified > 0) {
            const lines = this.formatLineNumbers(modifiedLines);
            summaries.push(`修改了${modified}行 (${lines})`);
        }
        if (added > 0) {
            const lines = this.formatLineNumbers(addedLines);
            summaries.push(`增加了${added}行 (${lines})`);
        }
        if (removed > 0) {
            const lines = this.formatLineNumbers(removedLines);
            summaries.push(`删除了${removed}行 (${lines})`);
        }

        if (summaries.length > 0) {
            const message = summaries.join('，');
            UIUtils.showToast(message, 'info', 4000);
        }
    }

    /**
     * 格式化行号列表
     * @param {Array} lineNumbers - 行号数组
     * @returns {string} 格式化后的字符串
     */
    formatLineNumbers(lineNumbers) {
        if (lineNumbers.length === 0) return '';
        if (lineNumbers.length <= 5) {
            return lineNumbers.join(', ');
        }

        // 如果行数太多，只显示前3个和最后1个
        const first = lineNumbers.slice(0, 3).join(', ');
        const last = lineNumbers[lineNumbers.length - 1];
        return `${first}...${last}`;
    }

    /**
     * 清除统计信息
     */
    clear() {
        if (this.originalStatsElement) {
            this.originalStatsElement.innerHTML = '';
        }
        if (this.modifiedStatsElement) {
            this.modifiedStatsElement.innerHTML = '';
        }
    }
}


// ========== TextComparator 主类 ==========
class TextComparator {
    constructor() {
        // DOM 元素引用
        this.originalEditor = document.getElementById('originalTextEditor');
        this.modifiedEditor = document.getElementById('modifiedTextEditor');
        this.originalDiffDisplay = document.getElementById('diffOriginal');
        this.modifiedDiffDisplay = document.getElementById('diffModified');

        // 状态
        this.originalText = '';
        this.modifiedText = '';
        this.diffs = [];

        // 子组件
        this.fileHandler = new FileHandler(this);
        this.sortManager = new SortManager(this);
        this.mergeManager = new MergeManager(this);
        this.statisticsManager = new StatisticsManager(this);
    }

    /**
     * 初始化
     */
    init() {
        // 初始化统计管理器
        const originalStats = document.getElementById('originalStats');
        const modifiedStats = document.getElementById('modifiedStats');
        this.statisticsManager.init(originalStats, modifiedStats);

        // 初始化排序下拉菜单
        const sortOriginalBtn = document.getElementById('sortOriginalText');
        const sortOriginalMenu = document.getElementById('sortOriginalMenu');
        this.sortManager.initDropdown('original', sortOriginalBtn, sortOriginalMenu);

        const sortModifiedBtn = document.getElementById('sortModifiedText');
        const sortModifiedMenu = document.getElementById('sortModifiedMenu');
        this.sortManager.initDropdown('modified', sortModifiedBtn, sortModifiedMenu);

        // 绑定事件监听器
        this.bindEvents();

        // 设置滚动同步
        this.setupScrollSync();
    }

    /**
     * 绑定事件监听器
     */
    bindEvents() {
        // 对比按钮
        document.getElementById('textDiffBtn').addEventListener('click', () => {
            this.compare();
        });

        // 清空按钮
        const clearOriginalBtn = document.getElementById('clearOriginalText');
        const clearModifiedBtn = document.getElementById('clearModifiedText');
        
        if (clearOriginalBtn) {
            clearOriginalBtn.addEventListener('click', () => {
                this.clearEditor('original');
            });
        }
        
        if (clearModifiedBtn) {
            clearModifiedBtn.addEventListener('click', () => {
                this.clearEditor('modified');
            });
        }

        // 导入文件按钮
        document.getElementById('importFileOriginal').addEventListener('click', () => {
            this.fileHandler.importFile('original');
        });

        document.getElementById('importFileModified').addEventListener('click', () => {
            this.fileHandler.importFile('modified');
        });

        // 导出文件按钮
        document.getElementById('exportOriginalText').addEventListener('click', () => {
            this.fileHandler.exportFile('original');
        });

        document.getElementById('exportModifiedText').addEventListener('click', () => {
            this.fileHandler.exportFile('modified');
        });

        // 复制按钮
        document.getElementById('copyOriginalText').addEventListener('click', () => {
            this.handleCopyClick('original');
        });

        document.getElementById('copyModifiedText').addEventListener('click', () => {
            this.handleCopyClick('modified');
        });

        // 合并所有按钮
        document.getElementById('mergeAllToModified').addEventListener('click', () => {
            this.mergeManager.mergeAll('left');
        });

        document.getElementById('mergeAllToOriginal').addEventListener('click', () => {
            this.mergeManager.mergeAll('right');
        });

        // 粘贴事件
        this.originalEditor.addEventListener('paste', (e) => this.handlePaste(e, this.originalEditor));
        this.modifiedEditor.addEventListener('paste', (e) => this.handlePaste(e, this.modifiedEditor));

        // 键盘快捷键
        document.addEventListener('keydown', (e) => {
            // Ctrl+K 或 Cmd+K: 对比
            if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
                e.preventDefault();
                this.compare();
            }
            // Ctrl+L 或 Cmd+L: 清空
            if ((e.ctrlKey || e.metaKey) && e.key === 'l') {
                e.preventDefault();
                this.clear();
            }
            // Escape: 关闭所有下拉菜单
            if (e.key === 'Escape') {
                this.sortManager.closeAllDropdowns();
            }
        });
    }

    /**
     * 处理粘贴事件
     * @param {ClipboardEvent} event
     * @param {HTMLTextAreaElement} editor
     */
    handlePaste(event, editor) {
        event.preventDefault();

        try {
            const text = event.clipboardData.getData('text/plain');
            if (!text) return;

            const start = editor.selectionStart;
            const end = editor.selectionEnd;
            const currentValue = editor.value;

            editor.value = currentValue.substring(0, start) + text + currentValue.substring(end);

            const newPosition = start + text.length;
            editor.selectionStart = newPosition;
            editor.selectionEnd = newPosition;
        } catch (error) {
            console.error('Paste error:', error);
        }
    }

    /**
     * 处理复制点击
     * @param {string} target - 'original' 或 'modified'
     */
    async handleCopyClick(target) {
        const text = this.getText(target);
        if (!text) {
            UIUtils.showToast('没有内容可复制', 'warning');
            return;
        }

        const success = await UIUtils.copyToClipboard(text);
        if (success) {
            UIUtils.showToast('内容已复制到剪贴板', 'success', 2000);
        } else {
            UIUtils.showToast('复制失败', 'error');
        }
    }

    /**
     * 获取文本
     * @param {string} target - 'original' 或 'modified'
     * @returns {string}
     */
    getText(target) {
        if (target === 'original') {
            return this.originalEditor.value;
        } else {
            return this.modifiedEditor.value;
        }
    }

    /**
     * 设置文本
     * @param {string} target - 'original' 或 'modified'
     * @param {string} text
     */
    setText(target, text) {
        if (target === 'original') {
            this.originalEditor.value = text;
            this.originalText = text;
        } else {
            this.modifiedEditor.value = text;
            this.modifiedText = text;
        }
    }

    /**
     * 对比文本
     */
    compare() {
        this.originalText = this.originalEditor.value;
        this.modifiedText = this.modifiedEditor.value;

        if (!this.originalText && !this.modifiedText) {
            UIUtils.showToast('请输入要对比的文本', 'warning');
            return;
        }

        // 对于大文件显示加载指示器
        const totalChars = this.originalText.length + this.modifiedText.length;
        let loadingIndicator = null;

        if (totalChars > 50000) {
            loadingIndicator = this.showLoadingIndicator('正在对比...');
        }

        // 使用 setTimeout 让 UI 有机会更新
        setTimeout(() => {
            try {
                // 计算智能差异（支持added/removed/modified）
                this.diffs = this.computeSmartDiff(this.originalText, this.modifiedText);

                // 渲染结果
                this.render();

                // 更新统计
                this.statisticsManager.update();
            } catch (error) {
                console.error('Comparison error:', error);
                UIUtils.showToast('对比失败', 'error');
            } finally {
                if (loadingIndicator) {
                    this.hideLoadingIndicator(loadingIndicator);
                }
            }
        }, 10);
    }

    /**
     * 智能差异计算（支持added/removed/modified）
     * @param {string} text1 - 原始文本
     * @param {string} text2 - 修改后文本
     * @returns {Array} 差异数组
     */
    computeSmartDiff(text1, text2) {
        const lines1 = text1.split('\n');
        const lines2 = text2.split('\n');

        // 使用标准LCS diff算法
        const editScript = this.computeEditScript(lines1, lines2);

        // 后处理：检测相邻的删除+插入是否应该合并为修改
        const optimizedScript = this.optimizeEditScript(editScript);

        // 转换为diff结果
        const diffs = [];
        let lineIndex = 0;

        for (const edit of optimizedScript) {
            if (edit.type === 'equal') {
                diffs.push({
                    type: 'equal',
                    lineIndex: lineIndex,
                    content1: edit.line,
                    content2: edit.line
                });
                lineIndex++;
            } else if (edit.type === 'delete') {
                diffs.push({
                    type: 'removed',
                    lineIndex: lineIndex,
                    content1: edit.line,
                    content2: ''
                });
                lineIndex++;
            } else if (edit.type === 'insert') {
                diffs.push({
                    type: 'added',
                    lineIndex: lineIndex,
                    content1: '',
                    content2: edit.line
                });
                lineIndex++;
            } else if (edit.type === 'modify') {
                const charDiff = this.computeCharDiff(edit.oldLine, edit.newLine);
                diffs.push({
                    type: 'modified',
                    lineIndex: lineIndex,
                    content1: edit.oldLine,
                    content2: edit.newLine,
                    charDiff: charDiff
                });
                lineIndex++;
            }
        }

        return diffs;
    }

    /**
     * 计算字符级差异（精确高亮）
     * @param {string} str1 - 原始字符串
     * @param {string} str2 - 修改后字符串
     * @returns {Object} 包含 html1 和 html2 的对象
     */
    computeCharDiff(str1, str2) {
        // 使用 Myers diff 算法计算字符级差异
        const diffs = this.myersDiff(str1, str2);
        
        let html1 = '';
        let html2 = '';
        
        for (const diff of diffs) {
            const escapedText = this.escapeHtml(diff.text);
            
            if (diff.type === 'equal') {
                html1 += escapedText;
                html2 += escapedText;
            } else if (diff.type === 'delete') {
                html1 += `<span class="diff-char">${escapedText}</span>`;
            } else if (diff.type === 'insert') {
                html2 += `<span class="diff-char">${escapedText}</span>`;
            }
        }
        
        return { html1, html2 };
    }

    /**
     * Myers diff 算法（字符级）
     * @param {string} str1
     * @param {string} str2
     * @returns {Array} 差异数组
     */
    myersDiff(str1, str2) {
        const n = str1.length;
        const m = str2.length;
        const max = n + m;
        
        // V 数组存储每个 k 线上的最远 x 坐标
        const v = {};
        v[1] = 0;
        
        const trace = [];
        
        for (let d = 0; d <= max; d++) {
            trace.push({ ...v });
            
            for (let k = -d; k <= d; k += 2) {
                let x;
                
                // 决定是向下还是向右移动
                if (k === -d || (k !== d && v[k - 1] < v[k + 1])) {
                    x = v[k + 1]; // 向下（插入）
                } else {
                    x = v[k - 1] + 1; // 向右（删除）
                }
                
                let y = x - k;
                
                // 沿对角线前进（相等的字符）
                while (x < n && y < m && str1[x] === str2[y]) {
                    x++;
                    y++;
                }
                
                v[k] = x;
                
                // 找到终点
                if (x >= n && y >= m) {
                    return this.backtrackDiff(str1, str2, trace, d);
                }
            }
        }
        
        // 如果没找到路径，返回简单的删除+插入
        return [
            { type: 'delete', text: str1 },
            { type: 'insert', text: str2 }
        ];
    }

    /**
     * 回溯构建差异序列
     * @param {string} str1
     * @param {string} str2
     * @param {Array} trace
     * @param {number} d
     * @returns {Array}
     */
    backtrackDiff(str1, str2, trace, d) {
        const diffs = [];
        let x = str1.length;
        let y = str2.length;
        
        for (let depth = d; depth >= 0; depth--) {
            const v = trace[depth];
            const k = x - y;
            
            let prevK;
            if (k === -depth || (k !== depth && v[k - 1] < v[k + 1])) {
                prevK = k + 1;
            } else {
                prevK = k - 1;
            }
            
            const prevX = v[prevK];
            const prevY = prevX - prevK;
            
            // 收集对角线上的相等字符
            while (x > prevX && y > prevY) {
                diffs.unshift({
                    type: 'equal',
                    text: str1[x - 1]
                });
                x--;
                y--;
            }
            
            if (depth === 0) break;
            
            // 添加插入或删除
            if (x === prevX) {
                // 插入
                diffs.unshift({
                    type: 'insert',
                    text: str2[y - 1]
                });
                y--;
            } else {
                // 删除
                diffs.unshift({
                    type: 'delete',
                    text: str1[x - 1]
                });
                x--;
            }
        }
        
        // 合并相邻的相同类型
        return this.mergeDiffs(diffs);
    }

    /**
     * 合并相邻的相同类型差异
     * @param {Array} diffs
     * @returns {Array}
     */
    mergeDiffs(diffs) {
        if (diffs.length === 0) return diffs;
        
        const merged = [];
        let current = { ...diffs[0] };
        
        for (let i = 1; i < diffs.length; i++) {
            if (diffs[i].type === current.type) {
                current.text += diffs[i].text;
            } else {
                merged.push(current);
                current = { ...diffs[i] };
            }
        }
        merged.push(current);
        
        return merged;
    }

    /**
     * 检测两行是否都是JSON属性定义
     * @param {string} line1 - 第一行
     * @param {string} line2 - 第二行
     * @returns {boolean} 如果两行都是JSON属性则返回true
     */
    areBothJsonProperties(line1, line2) {
        // 匹配JSON属性模式: "key": value
        const jsonPropertyPattern = /^\s*"[^"]+"\s*:\s*.+,?\s*$/;
        return jsonPropertyPattern.test(line1) && jsonPropertyPattern.test(line2);
    }

    /**
     * 提取行的结构模式（用占位符替换值）
     * @param {string} line - 要提取结构的行
     * @returns {string} 标准化的结构模式
     */
    extractStructure(line) {
        // 将字符串值替换为占位符
        let structure = line.replace(/"[^"]*"/g, '"X"');
        // 将数字替换为占位符
        structure = structure.replace(/\d+/g, 'N');
        return structure.trim();
    }

    /**
     * 检查两行是否具有相似的结构模式
     * @param {string} line1 - 第一行
     * @param {string} line2 - 第二行
     * @returns {boolean} 如果结构相似则返回true
     */
    haveSimilarStructure(line1, line2) {
        const structure1 = this.extractStructure(line1);
        const structure2 = this.extractStructure(line2);
        
        // 结构必须相同
        if (structure1 !== structure2) {
            return false;
        }
        
        // 对于JSON属性，还要检查属性名是否相同
        // 提取属性名（如果是JSON属性的话）
        const jsonPropertyPattern = /^\s*"([^"]+)"\s*:\s*.+,?\s*$/;
        const match1 = line1.match(jsonPropertyPattern);
        const match2 = line2.match(jsonPropertyPattern);
        
        if (match1 && match2) {
            // 两行都是JSON属性，检查属性名是否相同
            const key1 = match1[1];
            const key2 = match2[1];
            
            // 属性名必须相同才认为结构相似
            return key1 === key2;
        }
        
        // 如果不是JSON属性，只要结构相同就认为相似
        return true;
    }

    /**
     * 优化编辑脚本，将相似的删除+插入合并为修改
     * @param {Array} script - 原始编辑脚本
     * @returns {Array} 优化后的编辑脚本
     */
    optimizeEditScript(script) {
        const optimized = [];
        let i = 0;
        let mergeCount = 0;

        // 条件日志：记录初始编辑脚本
        if (window.DEBUG_DIFF) {
            console.group('Edit Script Optimization');
            console.log('Initial edit script:', script);
        }

        while (i < script.length) {
            const current = script[i];
            const next = script[i + 1];

            // 检查是否是相邻的删除+插入
            if (current && next &&
                current.type === 'delete' && next.type === 'insert') {

                // 计算相似度（降低阈值从0.3到0.2）
                const similarity = this.calculateSimilarity(current.line, next.line);

                // 使用新的灵活前缀检测方法
                const hasSignificantPrefix = this.hasSignificantCommonPrefix(current.line, next.line);

                // 检查是否都是JSON属性
                const isJsonProperty = this.areBothJsonProperties(current.line, next.line);

                // 检查是否具有相似的结构
                const hasSimilarStructure = this.haveSimilarStructure(current.line, next.line);

                // 合并条件（按性能优化顺序排列）
                // 1. 高相似度 - 快速检查
                // 2. 显著前缀 - 已计算
                // 3. 低相似度但是JSON属性 - 模式匹配
                // 4. 相似结构 - 最昂贵的检查
                const shouldMerge = similarity > 0.2 ||                    // 降低阈值到0.2
                    hasSignificantPrefix ||                 // 显著的相同前缀
                    (similarity > 0.1 && isJsonProperty) || // JSON属性且有一定相似度
                    hasSimilarStructure;                    // 结构相似

                if (shouldMerge) {
                    mergeCount++;
                    
                    // 条件日志：记录合并决策
                    if (window.DEBUG_DIFF) {
                        console.log(`Merge #${mergeCount}:`, {
                            similarity: similarity.toFixed(3),
                            hasSignificantPrefix,
                            isJsonProperty,
                            hasSimilarStructure,
                            oldLine: current.line.substring(0, 60) + (current.line.length > 60 ? '...' : ''),
                            newLine: next.line.substring(0, 60) + (next.line.length > 60 ? '...' : '')
                        });
                    }
                    
                    optimized.push({
                        type: 'modify',
                        oldLine: current.line,
                        newLine: next.line
                    });
                    i += 2; // 跳过两个
                    continue;
                }
            }

            // 否则保持原样
            optimized.push(current);
            i++;
        }

        // 记录优化结果
        console.log(`Edit script optimization complete: ${mergeCount} delete+insert pairs merged into modify operations`);
        
        if (window.DEBUG_DIFF) {
            console.log('Optimized edit script:', optimized);
            console.groupEnd();
        }

        return optimized;
    }

    /**
     * 获取两个字符串的相同前缀
     * @param {string} str1
     * @param {string} str2
     * @returns {string}
     */
    getCommonPrefix(str1, str2) {
        let i = 0;
        const minLen = Math.min(str1.length, str2.length);
        while (i < minLen && str1[i] === str2[i]) {
            i++;
        }
        return str1.substring(0, i);
    }

    /**
     * 检查两个字符串是否有显著的相同前缀
     * @param {string} str1 - 第一个字符串
     * @param {string} str2 - 第二个字符串
     * @returns {boolean} 如果前缀至少20个字符或占较短行的40%则返回true
     */
    hasSignificantCommonPrefix(str1, str2) {
        const commonPrefix = this.getCommonPrefix(str1, str2);
        const minLength = Math.min(str1.length, str2.length);
        
        // 至少20个字符 或 占较短行的40%
        return commonPrefix.length >= 20 || 
               (commonPrefix.length / minLength) >= 0.4;
    }

    /**
     * 计算两个字符串的相似度（0-1之间）
     * @param {string} str1
     * @param {string} str2
     * @returns {number}
     */
    calculateSimilarity(str1, str2) {
        if (str1 === str2) return 1;
        if (!str1 || !str2) return 0;

        const len1 = str1.length;
        const len2 = str2.length;
        const maxLen = Math.max(len1, len2);

        // 使用Levenshtein距离计算相似度
        const distance = this.levenshteinDistance(str1, str2);
        return 1 - (distance / maxLen);
    }

    /**
     * 计算Levenshtein距离
     * @param {string} str1
     * @param {string} str2
     * @returns {number}
     */
    levenshteinDistance(str1, str2) {
        const m = str1.length;
        const n = str2.length;
        const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));

        for (let i = 0; i <= m; i++) dp[i][0] = i;
        for (let j = 0; j <= n; j++) dp[0][j] = j;

        for (let i = 1; i <= m; i++) {
            for (let j = 1; j <= n; j++) {
                if (str1[i - 1] === str2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = Math.min(
                        dp[i - 1][j] + 1,     // 删除
                        dp[i][j - 1] + 1,     // 插入
                        dp[i - 1][j - 1] + 1  // 替换
                    );
                }
            }
        }

        return dp[m][n];
    }

    /**
     * 计算编辑脚本（基于LCS）
     * @param {Array} lines1 - 原始行数组
     * @param {Array} lines2 - 修改后行数组
     * @returns {Array} 编辑脚本
     */
    computeEditScript(lines1, lines2) {
        const m = lines1.length;
        const n = lines2.length;

        // 构建LCS长度表
        const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));

        for (let i = 1; i <= m; i++) {
            for (let j = 1; j <= n; j++) {
                if (lines1[i - 1] === lines2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        // 回溯构建编辑脚本
        const script = [];
        let i = m, j = n;

        while (i > 0 || j > 0) {
            if (i > 0 && j > 0 && lines1[i - 1] === lines2[j - 1]) {
                // 相同行
                script.unshift({
                    type: 'equal',
                    line: lines1[i - 1]
                });
                i--;
                j--;
            } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
                // 插入行
                script.unshift({
                    type: 'insert',
                    line: lines2[j - 1]
                });
                j--;
            } else if (i > 0) {
                // 删除行
                script.unshift({
                    type: 'delete',
                    line: lines1[i - 1]
                });
                i--;
            }
        }

        return script;
    }

    /**
     * 显示加载指示器
     * @param {string} message
     * @returns {HTMLElement}
     */
    showLoadingIndicator(message) {
        const indicator = document.createElement('div');
        indicator.className = 'loading-indicator';
        indicator.innerHTML = `
            <div class="loading-spinner"></div>
            <div style="margin-top: 10px;">${message}</div>
        `;
        document.body.appendChild(indicator);
        return indicator;
    }

    /**
     * 隐藏加载指示器
     * @param {HTMLElement} indicator
     */
    hideLoadingIndicator(indicator) {
        if (indicator && indicator.parentNode) {
            indicator.parentNode.removeChild(indicator);
        }
    }

    /**
     * 渲染差异结果
     */
    render() {
        // 使用 DocumentFragment 提高性能
        const fragmentOriginal = document.createDocumentFragment();
        const fragmentModified = document.createDocumentFragment();

        // 分别跟踪左右两侧的行号
        let lineNum1 = 0;
        let lineNum2 = 0;

        this.diffs.forEach((diff, index) => {
            // 渲染原始文本侧
            let content1 = '';
            let class1 = 'equal';
            let displayLineNum1 = '';

            if (diff.type === 'equal') {
                lineNum1++;
                content1 = this.escapeHtml(diff.content1);
                class1 = 'equal';
                displayLineNum1 = lineNum1;
            } else if (diff.type === 'removed') {
                lineNum1++;
                content1 = this.escapeHtml(diff.content1);
                class1 = 'removed';
                displayLineNum1 = lineNum1;
            } else if (diff.type === 'added') {
                content1 = ''; // 空行
                class1 = 'empty';
                displayLineNum1 = '';
            } else if (diff.type === 'modified') {
                lineNum1++;
                content1 = diff.charDiff ? diff.charDiff.html1 : this.escapeHtml(diff.content1);
                class1 = 'modified';
                displayLineNum1 = lineNum1;
            }

            const divOriginal = document.createElement('div');
            divOriginal.className = `diff-line ${class1}`;
            divOriginal.innerHTML = `
                <div class="diff-line-number">${displayLineNum1}</div>
                <div class="diff-line-content">${content1 || '&nbsp;'}</div>
            `;
            fragmentOriginal.appendChild(divOriginal);

            // 渲染修改文本侧
            let content2 = '';
            let class2 = 'equal';
            let displayLineNum2 = '';

            if (diff.type === 'equal') {
                lineNum2++;
                content2 = this.escapeHtml(diff.content2);
                class2 = 'equal';
                displayLineNum2 = lineNum2;
            } else if (diff.type === 'added') {
                lineNum2++;
                content2 = this.escapeHtml(diff.content2);
                class2 = 'added';
                displayLineNum2 = lineNum2;
            } else if (diff.type === 'removed') {
                content2 = ''; // 空行
                class2 = 'empty';
                displayLineNum2 = '';
            } else if (diff.type === 'modified') {
                lineNum2++;
                content2 = diff.charDiff ? diff.charDiff.html2 : this.escapeHtml(diff.content2);
                class2 = 'modified';
                displayLineNum2 = lineNum2;
            }

            const divModified = document.createElement('div');
            divModified.className = `diff-line ${class2}`;
            divModified.innerHTML = `
                <div class="diff-line-number">${displayLineNum2}</div>
                <div class="diff-line-content">${content2 || '&nbsp;'}</div>
            `;
            fragmentModified.appendChild(divModified);
        });

        // 一次性更新 DOM
        this.originalDiffDisplay.innerHTML = '';
        this.modifiedDiffDisplay.innerHTML = '';
        this.originalDiffDisplay.appendChild(fragmentOriginal);
        this.modifiedDiffDisplay.appendChild(fragmentModified);

        // 验证高亮显示的一致性
        this.validateHighlighting();
    }

    /**
     * 验证高亮显示的一致性
     * @returns {boolean} 如果高亮显示一致则返回true
     */
    validateHighlighting() {
        // 统计diffs数组中的modified类型数量
        const modifiedDiffsCount = this.diffs.filter(d => d.type === 'modified').length;
        
        // 统计DOM中实际渲染的modified行数量
        const renderedModifiedOriginal = this.originalDiffDisplay.querySelectorAll('.diff-line.modified').length;
        const renderedModifiedModified = this.modifiedDiffDisplay.querySelectorAll('.diff-line.modified').length;
        
        // 检查一致性
        const isConsistent = modifiedDiffsCount === renderedModifiedOriginal && 
                            modifiedDiffsCount === renderedModifiedModified;
        
        if (!isConsistent) {
            console.error('Highlighting inconsistency detected:', {
                expectedModified: modifiedDiffsCount,
                renderedOriginal: renderedModifiedOriginal,
                renderedModified: renderedModifiedModified
            });
        } else {
            console.log('Highlighting validation passed:', {
                modifiedLines: modifiedDiffsCount,
                renderedCorrectly: true
            });
        }
        
        return isConsistent;
    }

    /**
     * 设置滚动同步
     */
    setupScrollSync() {
        let isScrolling = false;

        const syncScroll = UIUtils.debounce(() => {
            isScrolling = false;
        }, 10);

        this.originalDiffDisplay.addEventListener('scroll', () => {
            if (!isScrolling) {
                isScrolling = true;
                this.modifiedDiffDisplay.scrollTop = this.originalDiffDisplay.scrollTop;
                syncScroll();
            }
        });

        this.modifiedDiffDisplay.addEventListener('scroll', () => {
            if (!isScrolling) {
                isScrolling = true;
                this.originalDiffDisplay.scrollTop = this.modifiedDiffDisplay.scrollTop;
                syncScroll();
            }
        });
    }

    /**
     * 清空编辑器
     * @param {string} target - 'original' 或 'modified'
     */
    clearEditor(target) {
        try {
            const editor = target === 'original' 
                ? this.originalEditor 
                : this.modifiedEditor;
            
            if (!editor) {
                console.warn(`Editor ${target} not found`);
                return;
            }
            
            // 清空编辑器内容
            editor.value = '';
            
            // 更新内部状态
            if (target === 'original') {
                this.originalText = '';
            } else {
                this.modifiedText = '';
            }
            
            // 清除对比结果显示
            const diffDisplayContainer = document.getElementById('diffDisplayContainer');
            if (diffDisplayContainer && this.diffs.length > 0) {
                this.originalDiffDisplay.innerHTML = '';
                this.modifiedDiffDisplay.innerHTML = '';
                this.diffs = [];
            }
            
            // 清除统计信息
            if (this.statisticsManager) {
                this.statisticsManager.clear();
            }
            
            const targetText = target === 'original' ? '原始文本' : '修改后文本';
            UIUtils.showToast(`${targetText}已清空`, 'success', 1500);
        } catch (error) {
            console.error('Error clearing editor:', error);
            UIUtils.showToast('清空失败', 'error');
        }
    }

    /**
     * 清空
     */
    clear() {
        this.originalEditor.value = '';
        this.modifiedEditor.value = '';
        this.originalText = '';
        this.modifiedText = '';
        this.diffs = [];

        this.originalDiffDisplay.innerHTML = '';
        this.modifiedDiffDisplay.innerHTML = '';

        this.statisticsManager.clear();

        UIUtils.showToast('已清空', 'info', 1500);
    }

    /**
     * HTML 转义
     * @param {string} text
     * @returns {string}
     */
    escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }
}

// ========== 初始化 ==========
let comparator;
document.addEventListener('DOMContentLoaded', () => {
    comparator = new TextComparator();
    comparator.init();
});
